package org.yu.api.register;

import net.minecraft.core.Holder;
import net.minecraft.data.worldgen.features.FeatureUtils;
import net.minecraft.data.worldgen.placement.PlacementUtils;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.VerticalAnchor;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration;
import net.minecraft.world.level.levelgen.placement.*;
import net.minecraft.world.level.levelgen.structure.templatesystem.RuleTest;

import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;

import static net.minecraft.data.worldgen.features.OreFeatures.DEEPSLATE_ORE_REPLACEABLES;
import static net.minecraft.data.worldgen.features.OreFeatures.STONE_ORE_REPLACEABLES;

@ParametersAreNonnullByDefault
@SuppressWarnings("unused")
public class OreFeatureBuilder {
    final LazyRegistry lazyRegistry;
    final String name;
    final BlockHolder<?> oreBlock;
    BlockHolder<?> deepOreBlock;
    RuleTest placeRule;
    final int veinPreChunk;
    float discardChanceOnAirExposure=0;
    private Predicate<Biome.BiomeCategory> generatePredicate;
    private final List<PlacementModifier> placementModifiers=new ArrayList<>();
    private final PlacedHolder placedHolder=new PlacedHolder();

    public OreFeatureBuilder(LazyRegistry lazyRegistry, String name,BlockHolder<?> oreBlock,int veinPreChunk) {
        this.lazyRegistry = lazyRegistry;
        this.name = lazyRegistry.modid+":"+name;
        this.oreBlock=oreBlock;
        this.veinPreChunk = veinPreChunk;
    }
    public OreFeatureBuilder deepOre(BlockHolder<?> deepOreBlock){
        this.deepOreBlock=deepOreBlock;
        return this;
    }
    public OreFeatureBuilder replaceRule(RuleTest ruleTest){
        this.placeRule=ruleTest;
        return this;
    }
    public OreFeatureBuilder generateOn(Predicate<Biome.BiomeCategory> biomePredicate){
        this.generatePredicate=biomePredicate;
        return this;
    }
    public OreFeatureBuilder withPlacementModifiers(PlacementModifier... modifiers){
        placementModifiers.addAll(List.of(modifiers));
        return this;
    }
    public OreFeatureBuilder withRange(int perVein,int minY,int maxY,boolean isUniform){
        placementModifiers.add(CountPlacement.of(perVein));
        placementModifiers.add(InSquarePlacement.spread());
        placementModifiers.add(BiomeFilter.biome());
        VerticalAnchor min = VerticalAnchor.absolute(minY);
        VerticalAnchor max = VerticalAnchor.absolute(maxY);
        placementModifiers.add( isUniform ? HeightRangePlacement.uniform(min, max) : HeightRangePlacement.triangle(min, max));
        return this;
    }
    /**
     * 矿物生成时不接触空气的机会
     * @param chance 机会
     */
    public OreFeatureBuilder discardChanceOnAirExposure(float chance){
        this.discardChanceOnAirExposure=chance;
        return this;
    }
    private Holder<ConfiguredFeature<OreConfiguration,?>> buildConfiguration(){
        List<OreConfiguration.TargetBlockState> targetBlockStates= new ArrayList<>();
        if(placeRule!=null)targetBlockStates.add(OreConfiguration.target(placeRule,oreBlock.get().defaultBlockState()));
        else {
            targetBlockStates.add(OreConfiguration.target(STONE_ORE_REPLACEABLES,oreBlock.get().defaultBlockState()));
            if(deepOreBlock!=null)targetBlockStates.add(OreConfiguration.target(DEEPSLATE_ORE_REPLACEABLES, deepOreBlock.get().defaultBlockState()));
        }
        return FeatureUtils.register(name, Feature.ORE,new OreConfiguration(targetBlockStates, veinPreChunk));
    }
    public PlacedHolder build(){
        lazyRegistry.runWhenCommonSetup.add(()->{
            if (placementModifiers.isEmpty()) {
                withRange(7, -20, 64, true);
            }
            var result = PlacementUtils.register(name, buildConfiguration(), placementModifiers);
            lazyRegistry.oreSpawnMap.put(result, Objects.requireNonNullElse(generatePredicate, biomeCategory -> true));
            placedHolder.holder=result;
        });
        return placedHolder;
    }
}
